package com.zbkj.front.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.json.JSONUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.zbkj.dal.base.constants.UserConstants;
import com.zbkj.dal.base.enums.*;
import com.zbkj.dal.base.page.CommonPage;
import com.zbkj.dal.common.utils.MoneyUtil;
import com.zbkj.dal.dao.*;
import com.zbkj.dal.entity.fund.UserFundAccount;
import com.zbkj.dal.entity.profit.ShareProfitRecord;
import com.zbkj.dal.entity.qrcode.Qrcode;
import com.zbkj.dal.entity.qrcode.QrcodeBusiness;
import com.zbkj.dal.entity.user.User;
import com.zbkj.dal.entity.user.UserActivityRecord;
import com.zbkj.dal.entity.user.UserToken;
import com.zbkj.dal.entity.user.UserWeekRecord;
import com.zbkj.dal.pojo.dto.UserOrderItemDTO;
import com.zbkj.dal.pojo.response.OrderFrontDataResponse;
import com.zbkj.dal.pojo.vo.WeChatMiniAuthorizeVo;
import com.zbkj.dal.token.FrontTokenComponent;
import com.zbkj.front.model.req.UserScanQrcodeReq;
import com.zbkj.front.service.FrontOrderService;
import com.zbkj.front.service.SpreadService;
import com.zbkj.service.manager.FundManager;
import com.zbkj.service.manager.QuotaManager;
import com.zbkj.service.manager.UserManager;
import com.zbkj.service.manager.WechatManager;
import com.zbkj.service.model.front.req.spread.FriendOrderReq;
import com.zbkj.service.model.front.req.spread.SpreadFriendReq;
import com.zbkj.service.model.front.req.spread.SpreadOrderReq;
import com.zbkj.service.model.front.vo.fund.UserQuotaVO;
import com.zbkj.service.model.front.vo.spread.*;
import com.zbkj.service.service.UserTokenService;
import com.zbkj.service.service.WechatService;
import com.zbkj.service.util.DateTimeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

@Slf4j
@Service
public class SpreadServiceImpl implements SpreadService {

    @Resource
    private UserDao userDao;

    @Resource
    private QrcodeDao qrcodeDao;

    @Resource
    private UserManager userManager;

    @Resource
    private FundManager fundManager;

    @Resource
    private QuotaManager quotaManager;

    @Resource
    private WechatService wechatService;

    @Resource
    private WechatManager wechatManager;

    @Resource
    private FrontOrderService frontOrderService;

    @Resource
    private QrcodeBusinessDao qrcodeBusinessDao;

    @Resource
    private FrontTokenComponent frontTokenComponent;

    @Resource
    private ShareProfitRecordDao shareProfitRecordDao;

    @Resource
    private UserActivityRecordDao userActivityRecordDao;

    @Resource
    private UserWeekRecordDao userWeekRecordDao;

    @Resource
    private UserBalanceRecordDao userBalanceRecordDao;

    @Resource
    private UserTokenDao userTokenDao;

    @Override
    public UserSpreadFundVO userSpreadFund() {
        Integer userId = frontTokenComponent.userId();
        UserFundAccount userFundAccount = fundManager.fundAccount(userId, FundAccountType.CRAB_ROE.name());
        BigDecimal totalReward = userWeekRecordDao.totalReward(userId);
        BigDecimal frozenAmount = userBalanceRecordDao.totalByTypeAndStatus(userId, FundTradeTypeEnums.SHARE_PROFIT.getCode(), FundStatusEnums.IN_TRANSIT.getCode());

        UserSpreadFundVO userSpreadFundVO = new UserSpreadFundVO();
        userSpreadFundVO.setTotalReward(MoneyUtil.prettyFormat(totalReward));
        userSpreadFundVO.setFrozenAmount(MoneyUtil.prettyFormat(frozenAmount));
        userSpreadFundVO.setWithdrawAmount(MoneyUtil.prettyFormat(userFundAccount.getAvailableAmount()));
        return userSpreadFundVO;
    }

    @Override
    public SpreadWeekRecordVO spreadWeekRecord() {
        Integer userId = frontTokenComponent.userId();
        UserWeekRecord userWeekRecord = userManager.selectWeeklyRecord(userId);
        SpreadWeekRecordVO spreadWeekRecordVO = new SpreadWeekRecordVO();
        int rewardRank = userWeekRecordDao.rewardRank(userWeekRecord.getReward(), DateTimeUtil.weekStart(), DateTimeUtil.weekEnd());
        int userCountRank = userWeekRecordDao.userCountRank(userWeekRecord.getUserCount(), DateTimeUtil.weekStart(), DateTimeUtil.weekEnd());
        int orderCountRank = userWeekRecordDao.orderCountRank(userWeekRecord.getOrderCount(), DateTimeUtil.weekStart(), DateTimeUtil.weekEnd());
        int orderAmountRank = userWeekRecordDao.orderAmountRank(userWeekRecord.getOrderAmount(), DateTimeUtil.weekStart(), DateTimeUtil.weekEnd());
        spreadWeekRecordVO.setRewardAmount(SpreadWeekRecordVO.generate(MoneyUtil.prettyFormat(userWeekRecord.getReward()), rewardRank));
        spreadWeekRecordVO.setRecommendCount(SpreadWeekRecordVO.generate(userWeekRecord.getUserCount().toString(), userCountRank));
        spreadWeekRecordVO.setOrderCount(SpreadWeekRecordVO.generate(userWeekRecord.getOrderCount().toString(), orderCountRank));
        spreadWeekRecordVO.setOrderAmount(SpreadWeekRecordVO.generate(MoneyUtil.prettyFormat(userWeekRecord.getOrderAmount()), orderAmountRank));
        return spreadWeekRecordVO;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public String userSpreadQrcode() {
        Integer userId = frontTokenComponent.userId();
        String ownerCode = String.valueOf(userId);
        return wechatManager.getQrcodePath(QrcodeTypeEnums.USER_SPREAD, ownerCode, null);
    }

    @Override
    public String merchantSpreadQrcode(Integer merchantId) {
        String ownerCode = String.valueOf(merchantId);
        return wechatManager.getQrcodePath(QrcodeTypeEnums.MERCHANT_SPREAD, ownerCode, null);
    }

    @Override
    public void userScanQrcode(UserScanQrcodeReq req) {
        log.info("用户扫码：{}", JSONUtil.toJsonStr(req));
        WeChatMiniAuthorizeVo response = wechatService.miniAuthCode(req.getCode());
        String openId = response.getOpenId();
        LambdaQueryWrapper<Qrcode> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Qrcode::getScene, req.getScene());
        wrapper.eq(Qrcode::getStatus, BooleanEnums.TRUE.getCode());
        wrapper.eq(Qrcode::getDeleted, BooleanEnums.FALSE.getCode());
        Qrcode qrcode = qrcodeDao.selectOne(wrapper);
        if (Objects.isNull(qrcode)) {
            log.error("场景值{}对应的太阳码不存在", req.getScene());
            return;
        }

        LambdaQueryWrapper<QrcodeBusiness> bizWrapper = new LambdaQueryWrapper<>();
        bizWrapper.eq(QrcodeBusiness::getScene, req.getScene());
        bizWrapper.eq(QrcodeBusiness::getStatus, BooleanEnums.TRUE.getCode());
        bizWrapper.eq(QrcodeBusiness::getDeleted, BooleanEnums.FALSE.getCode());
        QrcodeBusiness qrcodeBusiness = qrcodeBusinessDao.selectOne(bizWrapper);
        String qrcodeType = qrcodeBusiness.getQrcodeType();
        // 记录用户操作记录
        if (StringUtils.equals(qrcodeType, QrcodeTypeEnums.USER_SPREAD.getCode()) ||
                StringUtils.equals(qrcodeType, QrcodeTypeEnums.MERCHANT_SPREAD.getCode())) {
            UserActivityRecord userActivityRecord = new UserActivityRecord();
            userActivityRecord.setUserCode(openId);
            userActivityRecord.setActivityType(UserActivityTypeEnums.USER_SCAN_INVITE_QRCODE.getCode());
            userActivityRecord.setBizData(req.getScene());
            userActivityRecord.setActivityDigest(String.format("用户【%s】扫描太阳码，场景值【%s】", openId, req.getScene()));
            userActivityRecord.setCreateTime(LocalDateTime.now());
            userActivityRecord.setUpdateTime(LocalDateTime.now());
            userActivityRecord.setDeleted(BooleanEnums.FALSE.getCode());
            userActivityRecordDao.insert(userActivityRecord);
        }

        //绑定分享关系
        this.setUserToken(openId, req.getScene());
    }

    private Integer getSpreadPid(String scene) {
        LambdaQueryWrapper<QrcodeBusiness> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(QrcodeBusiness::getScene, scene);
        lambdaQueryWrapper.eq(QrcodeBusiness::getDeleted, false);
        lambdaQueryWrapper.last("limit 1");

        QrcodeBusiness qrcodeBusiness = qrcodeBusinessDao.selectOne(lambdaQueryWrapper);
        return qrcodeBusiness != null ? Integer.parseInt(qrcodeBusiness.getOwnerCode()) : 0;
    }

    public void setUserToken(String openId, String scene) {
        Integer spreadPid = this.getSpreadPid(scene);
        LambdaQueryWrapper<UserToken> lambdaQueryWrapper = new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(UserToken::getToken, openId);
        lambdaQueryWrapper.last("limit 1");
        UserToken getUserToken = userTokenDao.selectOne(lambdaQueryWrapper);
        UserToken userToken = new UserToken();
        if (getUserToken == null) {
            userToken.setToken(openId);
            userToken.setType(UserConstants.USER_TOKEN_TYPE_ROUTINE);
            userToken.setUid(0);
            userToken.setParentId(spreadPid);
            userTokenDao.insert(userToken);
        } else {
            userToken.setId(getUserToken.getId());
            userToken.setParentId(spreadPid);
            userTokenDao.updateById(userToken);
        }
    }

    @Override
    public List<SpreadFriendVO> friendList(SpreadFriendReq req) {
        LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
        Integer userId = Objects.isNull(req.getUserId()) ? frontTokenComponent.userId() : req.getUserId();
        wrapper.eq(User::getSpreadUid, userId);

        if (StringUtils.isNotBlank(req.getAccountOrName())) {
            wrapper.and(w -> w.eq(User::getAccount, req.getAccountOrName()).or().like(User::getNickname, req.getAccountOrName()));
        }

        // 查询所有一级好友信息
        List<User> friends = userDao.selectList(wrapper);
        if (CollectionUtils.isEmpty(friends)) {
            return new ArrayList<>();
        }

        // 是否查询二级
        List<User> resultFriendList = Objects.equals(req.getTier(), 1) ? friends :
                userManager.findByUserId(friends.stream().map(User::getId).collect(Collectors.toList()));

        if (CollectionUtils.isEmpty(resultFriendList)) {
            return new ArrayList<>();
        }

        // 查询用户对应的订单信息
        List<Integer> userIds = resultFriendList.stream().map(User::getId).collect(Collectors.toList());
        List<UserOrderItemDTO> userOrderItemDTOS = userWeekRecordDao.userSpreadItem(userIds);
        Map<Integer, UserOrderItemDTO> orderItemMap = userOrderItemDTOS.stream().collect(Collectors.toMap(UserOrderItemDTO::getUserId, Function.identity(), (a, b) -> a));

        // 组装结果
        List<SpreadFriendVO> spreadFriends = resultFriendList.stream().map(friend -> {
            SpreadFriendVO spreadFriendVO = new SpreadFriendVO();
            spreadFriendVO.setUserId(friend.getId());
            spreadFriendVO.setAvatar(friend.getAvatar());
            spreadFriendVO.setNickName(friend.getNickname());
            spreadFriendVO.setLevel(friend.getLevel());
            UserOrderItemDTO userOrderItemDTO = orderItemMap.get(friend.getId());
            if (Objects.nonNull(userOrderItemDTO)) {
                spreadFriendVO.setAmountCount(MoneyUtil.prettyFormat(userOrderItemDTO.getOrderAmount()));
                spreadFriendVO.setOrderCount(userOrderItemDTO.getOrderCount());
                spreadFriendVO.setLastTradeTime(userOrderItemDTO.getLastTime());
            } else {
                spreadFriendVO.setAmountCount(MoneyUtil.prettyFormat(BigDecimal.ZERO));
                spreadFriendVO.setOrderCount(0);
            }
            spreadFriendVO.setChildCount(friend.getSpreadCount());
            return spreadFriendVO;
        }).collect(Collectors.toList());
        if (Objects.nonNull(req.getOrderAmountOrder())) {
            if (Objects.equals(req.getOrderAmountOrder(), BooleanEnums.FALSE.getCode())) {
                spreadFriends.sort(Comparator.comparing(SpreadFriendVO::getAmountCount));
            } else {
                spreadFriends.sort(Comparator.comparing(SpreadFriendVO::getAmountCount).reversed());
            }
        }
        if (Objects.nonNull(req.getOrderCountOrder())) {
            if (Objects.equals(req.getOrderAmountOrder(), BooleanEnums.FALSE.getCode())) {
                spreadFriends.sort(Comparator.comparing(SpreadFriendVO::getOrderCount));
            } else {
                spreadFriends.sort(Comparator.comparing(SpreadFriendVO::getOrderCount).reversed());
            }
        }
        if (Objects.nonNull(req.getRecommendCountOrder())) {
            if (Objects.equals(req.getOrderAmountOrder(), BooleanEnums.FALSE.getCode())) {
                spreadFriends.sort(Comparator.comparing(SpreadFriendVO::getChildCount));
            } else {
                spreadFriends.sort(Comparator.comparing(SpreadFriendVO::getChildCount).reversed());
            }
        }
        if (Objects.nonNull(req.getMemberLevelOrder())) {
            if (Objects.equals(req.getOrderAmountOrder(), BooleanEnums.FALSE.getCode())) {
                spreadFriends.sort(Comparator.comparing(SpreadFriendVO::getLevel));
            } else {
                spreadFriends.sort(Comparator.comparing(SpreadFriendVO::getLevel).reversed());
            }
        }
        return spreadFriends;
    }

    @Override
    public FriendItemVO friendItem(Integer userId) {
        User user = userManager.findByUserId(userId);

        // 订单信息
        List<Integer> userIds = new ArrayList<>();
        userIds.add(user.getId());
        List<UserOrderItemDTO> userOrderItemDTOS = userWeekRecordDao.userSpreadItem(userIds);

        // 额度信息
        UserQuotaVO userQuota = quotaManager.userQuota(user.getId());

        FriendItemVO friendItemVO = new FriendItemVO();
        friendItemVO.setAvatar(user.getAvatar());
        friendItemVO.setNickName(user.getNickname());
        friendItemVO.setMobile(user.getAccount());

        // 查询上级推广人
        if (Objects.nonNull(user.getSpreadUid())) {
            User spreadUser = userManager.findByUserId(user.getSpreadUid());
            friendItemVO.setSuperiorPromoter(Optional.ofNullable(spreadUser).map(User::getNickname).orElse(null));
        }

        if (CollectionUtil.isNotEmpty(userOrderItemDTOS)) {
            UserOrderItemDTO userOrderItemDTO = userOrderItemDTOS.get(0);
            friendItemVO.setTotalOrderAmount(MoneyUtil.prettyFormat(userOrderItemDTO.getOrderAmount()));
            friendItemVO.setTotalOrderCount(userOrderItemDTO.getOrderCount());
        } else {
            friendItemVO.setTotalOrderAmount(MoneyUtil.prettyFormat(BigDecimal.ZERO));
            friendItemVO.setTotalOrderCount(0);
        }
        friendItemVO.setTotalQuota(userQuota.getTotalQuota());
        friendItemVO.setAvailableQuota(userQuota.getAvailableQuota());
        return friendItemVO;
    }

    @Override
    public CommonPage<SpreadOrderVO> spreadOrder(SpreadOrderReq req) {
        Integer userId = Objects.isNull(req.getUserId()) ? frontTokenComponent.userId() : req.getUserId();
        LambdaQueryWrapper<ShareProfitRecord> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(ShareProfitRecord::getPayeeCode, String.valueOf(userId));
        wrapper.eq(ShareProfitRecord::getDeleted, BooleanEnums.FALSE.getCode());
        wrapper.in(CollectionUtil.isNotEmpty(req.getTradeType()), ShareProfitRecord::getSceneCode, req.getTradeType());
        wrapper.in(CollectionUtil.isNotEmpty(req.getSettleStatus()), ShareProfitRecord::getShareStatus, req.getSettleStatus());
        if (StringUtils.isNotBlank(req.getTradeMonth())) {
            wrapper.ge(ShareProfitRecord::getBillDate, DateTimeUtil.monthBeginDate(req.getTradeMonth()));
            wrapper.le(ShareProfitRecord::getBillDate, DateTimeUtil.monthEndDate(req.getTradeMonth()));
        }
        if (StringUtils.isNotBlank(req.getSettleMonth())) {
            wrapper.ge(ShareProfitRecord::getFinishedTime, DateTimeUtil.monthBeginTime(req.getTradeMonth()));
            wrapper.le(ShareProfitRecord::getFinishedTime, DateTimeUtil.monthEndTime(req.getTradeMonth()));
        }
        wrapper.orderByDesc(ShareProfitRecord::getId);
        PageHelper.startPage(req.getPage(), req.getLimit());
        List<ShareProfitRecord> shareProfitRecords = shareProfitRecordDao.selectList(wrapper);

        List<SpreadOrderVO> spreadOrders = shareProfitRecords.stream().map(record -> {
            SpreadOrderVO spreadOrderVO = new SpreadOrderVO();
            spreadOrderVO.setTradeDate(LocalDateTimeUtil.format(record.getBillDate(), DatePattern.NORM_DATE_FORMATTER));
            spreadOrderVO.setOrderType(record.getSceneCode());
            spreadOrderVO.setOrderTypeDesc(ShareProfitSceneEnums.getDescByCode(record.getSceneCode()));
            spreadOrderVO.setStatus(record.getShareStatus());
            spreadOrderVO.setStatusDesc(ShareSettleStatusEnums.getDescByCode(record.getShareStatus()));
            spreadOrderVO.setImageUrl(record.getImagePath());
            if (StringUtils.equals(record.getSceneCode(), ShareProfitSceneEnums.RECRUIT.getCode())) {
                spreadOrderVO.setFirstLabel(String.format("新朋友：%s", record.getSourceUserName()));
                spreadOrderVO.setSecondLabel(String.format("首次提额：%s", record.getOrderAmount()));
                spreadOrderVO.setThirdLabel(String.format("拉新奖励：%s", record.getRealAmount()));
            } else {
                spreadOrderVO.setFirstLabel(String.format("订单：%s", record.getBizOrderNo()));
                spreadOrderVO.setSecondLabel(String.format("下单人：%s", record.getSourceUserName()));
                spreadOrderVO.setThirdLabel(String.format("订单金额：%s", record.getOrderAmount()));
            }
            if (StringUtils.equals(ShareSettleStatusEnums.SETTLED.getCode(), record.getShareStatus())) {
                String finishedDate = LocalDateTimeUtil.format(record.getFinishedTime(), DatePattern.NORM_DATE_FORMATTER);
                spreadOrderVO.setRemark(String.format(ShareSettleStatusEnums.SETTLED.getRemarkTemplate(), finishedDate, record.getRealAmount()));
            } else {
                String remarkTemplate = ShareSettleStatusEnums.getRemarkByCode(record.getShareStatus());
                spreadOrderVO.setRemark(Objects.isNull(remarkTemplate) ? null : String.format(remarkTemplate, record.getRealAmount()));
            }
            return spreadOrderVO;
        }).collect(Collectors.toList());

        CommonPage<SpreadOrderVO> result = new CommonPage<>();
        PageInfo<ShareProfitRecord> pageInfo = new PageInfo<>(shareProfitRecords);
        result.setTotalPage(pageInfo.getPages());
        result.setPage(pageInfo.getPageNum());
        result.setLimit(pageInfo.getPageSize());
        result.setTotal(pageInfo.getTotal());
        result.setList(spreadOrders);
        return result;
    }

    @Override
    public CommonPage<OrderFrontDataResponse> friendOrder(FriendOrderReq req) {
        return CommonPage.restPage(frontOrderService.list(req.getUserId(), 1, req));
    }
}
